package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.mapper.TeachplanMediaMapper;
import com.xuecheng.content.model.dto.BindTeachplanMediaDto;
import com.xuecheng.content.model.dto.SaveTeachplanDto;
import com.xuecheng.content.model.dto.TeachPlanDto;
import com.xuecheng.content.model.po.Teachplan;
import com.xuecheng.content.model.po.TeachplanMedia;
import com.xuecheng.content.service.TeachPlanService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class TeachPlanServiceImpl implements TeachPlanService {

    private final TeachplanMapper teachplanMapper;

    private final TeachplanMediaMapper teachplanMediaMapper;

    /**
     * 根据课程id查询课程计划
     *
     * @param courseId 课程计划id
     * @return 课程计划信息
     */
    @Override
    public List<TeachPlanDto> findTeachplanTree(Long courseId) {
        return teachplanMapper.selectTreeNodes(courseId);
    }

    /**
     * 新增/修改/保存课程计划
     *
     * @param saveTeachplanDto
     */
    @Override
    public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) {
        // 通过课程计划id判断是新增还是修改
        Long teachplanId = saveTeachplanDto.getId();
        if (teachplanId == null) {
            // 新增
            Teachplan teachplan = new Teachplan();
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);
            // 确定排序字段 找到同级节点个数，排序字段就是个数加1
            Long courseId = saveTeachplanDto.getCourseId();
            Long parentid = saveTeachplanDto.getParentid();
            int count = getTeachplanCount(courseId, parentid);
            teachplan.setOrderby(count + 1);

            teachplanMapper.insert(teachplan);
        } else {
            // 修改
            // 先查询出原来的数据
            Teachplan teachplan = teachplanMapper.selectById(teachplanId);
            // 将要修改的数据拷贝的原来的数据中
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);
            teachplanMapper.updateById(teachplan);
        }
    }

    /**
     * 删除课程计划
     *
     * @param id 课程计划id
     */
    @Transactional // 因为操作了多张数据表，所以加上事务注解
    @Override
    public void deleteTeachplan(Long id) {
        // 根据课程计划id,判断当前节点是一级节点(根节点)还是二级节点
        Teachplan teachplan = teachplanMapper.selectById(id);
        if (teachplan.getGrade().equals(1)) {
            // 说明当前是一级节点
            // 删除一级节点的条件：一级节点下面没有子节点才可以删除
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<Teachplan>()
                    .eq(Teachplan::getParentid, id);
            Integer count = teachplanMapper.selectCount(queryWrapper);
            if (count > 0) {
                // 说明一级节点下面有数据，不能删除
                XueChengPlusException.cast("当前节点下面有子节点，不能删除");
            }
            // 说明：删除一级节点
            int i = teachplanMapper.deleteById(id);
            if (i <= 0) {
                XueChengPlusException.cast("删除课程计划失败");
            }
        } else {
            // 说明是二级节点，直接删除
            teachplanMapper.deleteById(id);
            // 判断当前节点是否关联了媒资信息
            LambdaQueryWrapper<TeachplanMedia> queryWrapper = new LambdaQueryWrapper<TeachplanMedia>()
                    // 构建查询条件
                    .eq(TeachplanMedia::getTeachplanId, id);
            // 查询课程计划对应的媒资信息
            TeachplanMedia teachplanMedia = teachplanMediaMapper.selectOne(queryWrapper);
            if (teachplanMedia == null) {
                // 说明课程计划，没有关联媒资信息，直接结束
                return;
            }
            // 删除对应的媒资信息
            teachplanMediaMapper.deleteById(teachplanMedia.getId());
        }
        teachplanMapper.deleteById(teachplan);
    }

    /**
     * 移动课程计划
     *
     * @param id       课程计划id
     * @param moveType 移动的类型
     */
    @Override
    public void moveTeachplan(Long id, String moveType) {
        // 1.参数的合法性校验
        // StringUtils.isBlank(moveType) 校验字符串是否为空或者是空白字符串
        if (StringUtils.isBlank(moveType) || id == null) {
            throw new RuntimeException("移动类型为空或者课程计划id为空");
        }

        if (!"moveup".equals(moveType) && !"movedown".equals(moveType)) {
            throw new RuntimeException("移动类型不正确");
        }

        // 2.根据课程计划id查询出当前课程计划
        Teachplan teachplan = teachplanMapper.selectById(id);
        // 取出当前节点的类型
        Integer grade = teachplan.getGrade();
        if (grade == 1) {
            // 说明是一级节点
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<Teachplan>()
                    // 这里为什么是0L，因为一级节点的父节点是0
                    .eq(Teachplan::getParentid, 0L).orderByAsc(Teachplan::getOrderby);
            List<Teachplan> teachplans = teachplanMapper.selectList(queryWrapper);

            //移动
            move(teachplans, teachplan, moveType);
        } else {
            // 说明是二级节点
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<Teachplan>()
                    .eq(Teachplan::getParentid, teachplan.getParentid()).orderByAsc(Teachplan::getOrderby);
            List<Teachplan> teachplans = teachplanMapper.selectList(queryWrapper);

            // 移动
            move(teachplans, teachplan, moveType);
        }
    }

    /**
     * 课程计划和媒资信息绑定
     *
     * @param bindTeachplanMediaDto 课程计划和媒资信息绑定信息
     */
    @Override
    public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto) {
        // 获取课程计划id
        Long teachplanId = bindTeachplanMediaDto.getTeachplanId();
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);

        // 先删除原来绑定的数据 根据课程计划id删除绑定媒资信息
        int delete = teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>()
                .eq(TeachplanMedia::getTeachplanId, bindTeachplanMediaDto.getTeachplanId()));
        if (delete <= 0) {
            XueChengPlusException.cast("删除课程计划媒资信息失败");
        }
        // 添加新记录
        TeachplanMedia teachplanMedia = new TeachplanMedia();
        BeanUtils.copyProperties(bindTeachplanMediaDto, teachplanMedia);
        teachplanMedia.setCourseId(teachplan.getCourseId());
        teachplanMedia.setMediaFilename(bindTeachplanMediaDto.getFileName());
        teachplanMediaMapper.insert(teachplanMedia);
    }

    /**
     * @param teachplans 当前节点的所有子节点
     * @param teachplan  当前课程计划
     * @param moveType   移动的类型 是上移 还是 下移
     */
    public void move(List<Teachplan> teachplans, Teachplan teachplan, String moveType) {
        // 先获取当前课程计划在集合中的索引 因为teachplans 表示的是当前节点的所有子节点
        int index = teachplans.indexOf(teachplan);
        // 获取当前课程计划的排序字段
        Integer orderby = teachplan.getOrderby();
        if ("moveup".equals(moveType)) {
            // 上移
            if (index == 0) {
                XueChengPlusException.cast("当前已经处于最上面的位置，无法继续上移了");
            }

            // 交换课程计划的排序值
            // 获取上一个课程计划
            Teachplan lastTeachplan = teachplans.get(index - 1);
            // 取出上一个课程计划的排序值
            Integer lastOrderby = lastTeachplan.getOrderby();
            // 交换两个排序值
            teachplan.setOrderby(lastOrderby);
            lastTeachplan.setOrderby(orderby);
            // 执行更新
            teachplanMapper.updateById(teachplan);
            teachplanMapper.updateById(lastTeachplan);
        } else {
            // 下移
            int max = teachplans.size() - 1; // 获取集合中最后一个元素的索引
            if (index == max) {
                XueChengPlusException.cast("当前已经处于最下面的位置，无法继续下移了");
            }

            // 交换课程计划的排序字段
            // 获取下一个课程计划
            Teachplan nextTeachplan = teachplans.get(index + 1);
            // 去出下一个课程计划的排序值
            Integer nextOrderBy = nextTeachplan.getOrderby();
            // 交换两个排序值
            teachplan.setOrderby(nextOrderBy);
            nextTeachplan.setOrderby(orderby);
            // 执行更新
            teachplanMapper.updateById(teachplan);
            teachplanMapper.updateById(nextTeachplan);
        }
    }


    private int getTeachplanCount(Long courseId, Long parentId) {
        // 构建查询条件
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<Teachplan>()
                .eq(Teachplan::getCourseId, courseId)
                .eq(Teachplan::getParentid, parentId);
        Integer count = teachplanMapper.selectCount(queryWrapper);
        return count + 1;
    }
}
